﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.Simulation.LogicalGate
{
    /// <summary>
    /// This class represents a byte which contains eight bits.
    /// </summary>
    [Serializable]
    public class Byte : IByte
    {
        /// <summary>
        /// This field holds the bits of the byte.
        /// </summary>
        private readonly Bit[] bits;

        /// <summary>
        /// Initializes a new instance of the <see cref="Byte"/> class.
        /// </summary>
        public Byte()
        {
            this.bits = new Bit[8];

            for (int i = 0; i < 8; i++)
            {
                this.bits[i] = new Bit(false);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Byte"/> class.
        /// </summary>
        /// <param name="value">The byte to clone.</param>
        public Byte(Byte value)
        {
            if (value == (Byte) null)
            {
                throw new ArgumentNullException("value");
            }

            this.bits = (Bit[]) value.Bits.Clone();
        }

        /// <summary>
        /// Gets or sets the bit at position 0.
        /// </summary>
        /// <value>The bit at position 0.</value>
        public Bit Bit0
        {
            get { return Bits[0]; }
            set { Bits[0] = value; }
        }

        /// <summary>
        /// Gets or sets the bit at position 1.
        /// </summary>
        /// <value>The bit at position 1.</value>
        public Bit Bit1
        {
            get { return Bits[1]; }
            set { Bits[1] = value; }
        }

        /// <summary>
        /// Gets or sets the bit at position 2.
        /// </summary>
        /// <value>The bit at position 2.</value>
        public Bit Bit2
        {
            get { return Bits[2]; }
            set { Bits[2] = value; }
        }

        /// <summary>
        /// Gets or sets the bit at position 3.
        /// </summary>
        /// <value>The bit at position 3.</value>
        public Bit Bit3
        {
            get { return Bits[3]; }
            set { Bits[3] = value; }
        }

        /// <summary>
        /// Gets or sets the bit at position 4.
        /// </summary>
        /// <value>The bit at position 4.</value>
        public Bit Bit4
        {
            get { return Bits[4]; }
            set { Bits[4] = value; }
        }

        /// <summary>
        /// Gets or sets the bit at position 5.
        /// </summary>
        /// <value>The bit at position 5.</value>
        public Bit Bit5
        {
            get { return Bits[5]; }
            set { Bits[5] = value; }
        }

        /// <summary>
        /// Gets or sets the bit at position 6.
        /// </summary>
        /// <value>The bit at position 6.</value>
        public Bit Bit6
        {
            get { return Bits[6]; }
            set { Bits[6] = value; }
        }

        /// <summary>
        /// Gets or sets the bit at position 7.
        /// </summary>
        /// <value>The bit at position 7.</value>
        public Bit Bit7
        {
            get { return Bits[7]; }
            set { Bits[7] = value; }
        }

        /// <summary>
        /// Gets or sets the bits of the byte.
        /// </summary>
        /// <value>The bits of the byte.</value>
        public Bit[] Bits
        {
            get { return bits; }
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="a">The first byte.</param>
        /// <param name="b">The second byte.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator ==(Byte a, Byte b)
        {
            if (System.Object.ReferenceEquals(a, b))
            {
                return true;
            }

            if (((object) a == null) || ((object) b == null))
            {
                return false;
            }

            for (int i = 0; i < 8; i++)
            {
                if (a.Bits[i].State != b.Bits[i].State)
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="a">The first byte.</param>
        /// <param name="b">The second byte.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator !=(Byte a, Byte b)
        {
            return !(a == b);
        }

        /// <summary>
        /// Compares the current instance of a byte instance to another.
        /// </summary>
        /// <param name="compare">The byte instance to compare.</param>
        /// <returns>True if the bit states is even to the specified byte instance 
        /// otherwise, false</returns>
        public bool CompareTo(Byte compare)
        {
            if (compare == (Byte) null)
            {
                throw new ArgumentNullException("compare");
            }

            for (int i = 0; i < 8; i++)
            {
                if (compare.Bits[i] != this.bits[i])
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Copies the current instance.
        /// </summary>
        /// <returns>A copy of the current instance.</returns>
        public Byte Copy()
        {
            Byte result = new Byte();

            for (int i = 0; i < 8; i++)
            {
                result.Bits[i] = this.bits[i];
            }

            return result;
        }

        /// <summary>
        /// Shifts left.
        /// </summary>
        public void ShiftLeft()
        {
            for (int i = this.bits.Length - 1; i > 0; i--)
            {
                this.bits[i] = this.bits[i - 1];
            }

            this.bits[0].State = false;
        }

        /// <summary>
        /// Shifts right.
        /// </summary>
        public void ShiftRight()
        {
            for (int i = 1; i < this.bits.Length; i++)
            {
                this.bits[i - 1] = this.bits[i];
            }

            this.bits[this.bits.Length - 1].State = false;
        }

        /// <summary>
        /// Shifts left.
        /// </summary>
        /// <param name="times">The number of times to shift.</param>
        public void ShiftLeft(int times)
        {
            for (int i = 0; i < times; i++)
            {
                this.ShiftLeft();
            }
        }

        /// <summary>
        /// Shifts right.
        /// </summary>
        /// <param name="times">The number of times to shift.</param>
        public void ShiftRight(int times)
        {
            for (int i = 0; i < times; i++)
            {
                this.ShiftRight();
            }
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            String result = "";

            for (int i = 0; i < this.bits.Length; i++)
            {
                result += this.bits[i].ToString();
            }

            return result;
        }
    }
}